// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

module sys_check
  (
   // ------------------------
   // Clock and Reset signals
   // ------------------------
   input       iClk, //clock for sequential logic 
   input       iRst_n, //reset signal from PLL Lock, resets state machine to initial state
   // ----------------------------
   // inputs and outputs
   // ---------------------------- 
   input [1:0] ivCPU_SKT_OCC, //Socket occupied (input vector for CPU0 and CPU1 SKT_OCC signal)
   input [1:0] ivPROC_ID_CPU0, //CPU0 Processor ID
   input [1:0] ivPROC_ID_CPU1, //CPU1 Processor ID
   input [2:0] ivPKG_ID_CPU0, //CPU0 Package ID
   input [2:0] ivPKG_ID_CPU1, //CPU1 Package ID
   input [1:0] ivCPU_INTR_CABLE_PRSNT_N, //Interposer cable present, CPU0/1 interposer  // These 2 signals come from debug FPGA via sGPIO
   
   output      oCpu0IntrPrsnt_n, //these are to share thru ESPI/CS1 with CPU
   output      oCpu1IntrPrsnt_n,
   output      oCpu0IntrTypeABn,
   output      oCpu1IntrTypeABn,
   
   output reg  oSYS_OK, //System validation Ok, once this module has detected a valid CPU configurqation this signal will be set 
   output reg  oCPU_MISMATCH, //CPU Mismatch, if not CPU ID or PKG ID were identified then this signal will remain low, this signal is used in BMC SGPIOs module
   output reg  oHBM, //Output enabler for HBM VR
   output reg  oSOCKET_REMOVED, //Socket Removed
   input rjo_ready,  
   input rjo_ready_sec
  
   
   
   );
   
   //////////////////////////////////////////////////////////////////////////////////
    // States for FSM
   //////////////////////////////////////////////////////////////////////////////////
   localparam INIT                   = 4'd0;
   localparam VALID_CPU0             = 4'd1;
   localparam VALID_CPU1             = 4'd2;
   localparam SYS_OK_HBM             = 4'd3;
   localparam SYS_OK                 = 4'd4;
   localparam CPU_MISMATCH           = 4'd5;
   localparam SKT_REMOVED            = 4'd6;
   
   //////////////////////////////////////////////////////////////////////////////////
   // Parameters
   //////////////////////////////////////////////////////////////////////////////////
   localparam  LOW =1'b0;
   localparam  HIGH=1'b1;
   
   //PROC_ID[1:0]
   localparam  GNR         = 2'b00;  //GNR
   localparam  SRF         = 2'b01;  //SRF
   localparam  Reserved    = 2'b10;  //Reserved
   localparam  CWF         = 2'b11;  //CWF
   
   //PKG_ID[2:0]
   localparam  STD_PKG     = 3'b000;  //Standard Pakgage
   localparam  RSVD_PKG1   = 3'b001;  //Reserved
   localparam  HBM         = 3'b010;
   localparam  RIO_1S      = 3'b011;  //Rich IO Signle Socket
   localparam  BOARD       = 3'b111;  //Board default
   
   //state
   reg [3:0]   state;
   reg rCPU1_PRESENT;
   
   intr_detect skt0
     (
      .iSktOcc_n(ivCPU_SKT_OCC[0]),
      .iCpuProcId(ivPROC_ID_CPU0),
      .iCpuPkgId(ivPKG_ID_CPU0),
      .oIntrPrsnt_n(oCpu0IntrPrsnt_n),
      .oIntrSel(oCpu0IntrTypeABn)
      );
   
   intr_detect skt1
     (
      .iSktOcc_n(ivCPU_SKT_OCC[1]),
      .iCpuProcId(ivPROC_ID_CPU1),
      .iCpuPkgId(ivPKG_ID_CPU1),
      .oIntrPrsnt_n(oCpu1IntrPrsnt_n),
      .oIntrSel(oCpu1IntrTypeABn)
      );
   
   
   
   
   //////////////////////////////////////////////////////////////////////////////////
       // Sys_check FSM logic
   //////////////////////////////////////////////////////////////////////////////////
   
   always @(posedge iClk or negedge iRst_n) 
   begin
	    if(!iRst_n) 
		begin								//reset state
			state 				<= INIT;
			oSYS_OK 			<= LOW;				//Initail state for system ok
		    oCPU_MISMATCH 		<= LOW;				//Initail state for CPU mismatch         
			oHBM            	<= LOW;        	//Output enabler for HBM VR
			oSOCKET_REMOVED 	<= LOW;				//Initail state for SKT_REMOVED
			rCPU1_PRESENT       <= LOW;
	    end
	    
	    else 
		begin
		     //If no interposer is detected or properly connected
		     if({oCpu1IntrPrsnt_n, oCpu0IntrPrsnt_n} == 2'b11) begin	 
			      case(state)
				      INIT: begin
					      if(rjo_ready && rjo_ready_sec) begin
						if (ivCPU_SKT_OCC[0] == LOW) begin		//verify CPU0 is present
						        state <= VALID_CPU0;
					       end
					       else begin
						        state <= INIT;								//CPU0 is not present
					       end
						  end
				      end // case: INIT
				      
				      VALID_CPU0: begin
					       if((ivPROC_ID_CPU0 == GNR || ivPROC_ID_CPU0 == SRF || ivPROC_ID_CPU0 == CWF) && ivCPU_SKT_OCC[1] == HIGH) begin		//If CPU0 is a GNR and CPU1 not present then check if CPU0 SKU is valid
						        case (ivPKG_ID_CPU0)
							        STD_PKG: state <= SYS_OK;			//CPU0 pakgage type is standard, supported
							        HBM:		state <= SYS_OK_HBM;    //CPU0 pakgage type is HBM, supported
							        RIO_1S:	state <= SYS_OK;    		//CPU0 pakgage type is Rich IO 1S, supported
							        BOARD:	state <= SYS_OK;			//no CPUs
							        default:	state <= CPU_MISMATCH;	//other cases CPU0 is not supported
						        endcase
					       end
					       else if ((ivPROC_ID_CPU0 == GNR || ivPROC_ID_CPU0 == SRF || ivPROC_ID_CPU0 == CWF) && ivCPU_SKT_OCC[1] == LOW) begin	//CPU1 is present
						        state <= VALID_CPU1;						//Next state -> check if CPU1 is valid
					       end
					       else begin
						        state <= CPU_MISMATCH;
					       end
				      end //case: VALID_CPU0
				      
				      VALID_CPU1: begin
					  rCPU1_PRESENT <= HIGH;
					       if ((ivPROC_ID_CPU1 == GNR || ivPROC_ID_CPU1 == SRF || ivPROC_ID_CPU1 == CWF) && ivCPU_SKT_OCC[1] == LOW) begin       //If CPU1 is a GNR then check both CPUs are compatible
						        case ({ivPKG_ID_CPU0, ivPKG_ID_CPU1})
							        {STD_PKG, STD_PKG}:	state <= SYS_OK;		//Supported
							        {HBM, HBM}:			  	state <= SYS_OK_HBM;
							        {RIO_1S, RIO_1S}:	  	state <= CPU_MISMATCH;
									                                                
							        {BOARD, BOARD}:	  	state <= SYS_OK;		//no CPUs
							        default: 				state	<= CPU_MISMATCH;
						        endcase
					       end
					       else begin
						        state <= CPU_MISMATCH;
					       end
				      end //case: VALID_CPU1
				      
				      SYS_OK: begin				//once enter this state, FSM won't go out of this state unless an AC cycling issued or detect CPU is removed
					       oSYS_OK	<=	HIGH;
					       
					       if ((ivCPU_SKT_OCC[0] == HIGH) || (ivCPU_SKT_OCC[1] == HIGH && rCPU1_PRESENT)) begin //If CPU0 or CPU1 is removed 
						        state <= SKT_REMOVED;
					       end
					       else begin
						        state <= SYS_OK;
					       end
				      end //case:SYS_OK
				      
				      SYS_OK_HBM: begin				//once enter this state, FSM won't go out of this state unless an AC cycling issued or detect CPU is removed
					       oSYS_OK	<=	HIGH;
					       oHBM		<= HIGH;
					       
					       if ((ivCPU_SKT_OCC[0] == HIGH) || (ivCPU_SKT_OCC[1] == HIGH )) begin //If CPU0 or CPU1 is removed 
						        state <= SKT_REMOVED;
					       end
					       else begin
						        state <= SYS_OK;
					       end
				      end //case:SYS_OK_HBM
				      
				      CPU_MISMATCH: begin						//The only way to get out of this state is AC cycle 
					       oSYS_OK 				<= LOW;			//System not boot
					       oCPU_MISMATCH 		<= HIGH;			//CPU mismatch to BMC via sGPIO
					       state 				<= CPU_MISMATCH;
				      end //case: CPU_MISMATCH
				      
				      SKT_REMOVED: begin						//The only way to get out of this state is AC cycle
					       oSYS_OK				<= LOW;			//System not boot
					       oSOCKET_REMOVED 	<= HIGH;			//Fault state, CPU removed while system was on
					       state 				<= SKT_REMOVED;
				      end
				      
				      default: begin
					       state	<= INIT;
				      end
			      endcase //endcase
		     end
		     
		     else begin
		        oSYS_OK <= LOW;
		     end
	    end
   end
   
   
   
   
   
endmodule



